import os
import asyncio  # 用于异步操作
import shutil  # 用于文件操作
import time
from pathlib import Path  # 用于路径操作
from tempfile import NamedTemporaryFile  # 用于创建临时文件
from typing import List, Any, Union, Optional  # python3.5开始引入的，强化类型定义

from fastapi import APIRouter, Depends
from fastapi import File, UploadFile  # 用于上传文件
from fastapi import Query  # 用于查询参数
from fastapi import Form  # 用于表单格式提交
from fastapi import Request  # 用于获取请求信息
from fastapi.staticfiles import StaticFiles  # 用于请求静态文件,app里注册
from fastapi.templating import Jinja2Templates  # 用于渲染模板
templates = Jinja2Templates(directory="templates")  # 指定模板目录
from sqlalchemy.ext.asyncio import AsyncSession


from schemas.response import resp  # 导入自定义的响应体
from dependencies.deps import get_db  # 导入数据库连接
from core.config import settings
from services.user import UserService
from common import logger  # 导入日志记录器
from dependencies.sys_redis import redis_client
from schemas.request.test import UserIn, UserOut

router = APIRouter()

"""
api文件中router装饰器方法参数

经常使用的参数：
path：接口路径
summary：接口概要
description：接口详细描述
response_description：接口响应描述
deprecated：是否废弃，为True时，在OpenAPI文档中会显示为已弃用
"""


@router.get('/', summary='接口概要在summary参数中定义', description='接口详细描述在description参数中定义',
            response_description='接口响应描述在response_description参数中定义', deprecated=False)
async def test_get():
    return {'method': 'get方法'}


@router.post('/', summary='测试post方法')
async def test_post():
    return {'method': 'post方法'}


@router.put('/', summary='测试put方法')
async def test_put():
    return {'method': 'put方法'}


@router.patch('/', summary='测试patch方法', deprecated=True)
async def test_patch():
    return {'method': 'patch方法'}


@router.delete('/', summary='测试delete方法')
async def test_delete():
    return {'method': 'delete方法'}


@router.get("/user/{user_id}", summary="测试路径参数，获取指定用户id信息")
async def test_get_user(user_id: int, db: AsyncSession = Depends(get_db)):
    user = UserService.get_user_by_id(db, user_id)
    if not user:
        return resp.fail(resp.DataNotFound)
    return resp.ok(data=user.dict())


@router.post("/login", summary="测试请求体参数")
async def test_post_body(body: UserIn, db: AsyncSession = Depends(get_db)):
    logger.info(body.dict())
    logger.info(type(body))
    return resp.ok(data=body.dict())


@router.post("/regin", summary="测试form表单数据提交")
async def test_post_from(username: str = Form(...), password: str = Form(...), db: AsyncSession = Depends(get_db)):
    logger.info(username)
    logger.info(password)
    return resp.ok(data={"username": username, "password": password})


@router.get("/all", summary="测试获取分页数据")
async def test_get_all_user(page: int = 1, page_size: int = 20, db: AsyncSession = Depends(get_db)):
    try:
        # 假设 UserService.get_users 返回用户列表和总数
        users, total = UserService.get_users(db, page, page_size)

        # 计算分页信息
        total_pages = (total + page_size - 1) // page_size
        has_next = page < total_pages
        has_previous = page > 1

        # 构建分页信息
        pagination = {
            "page": page,
            "page_size": page_size,
            "total": total,
            "total_pages": total_pages,
            "has_next": has_next,
            "has_previous": has_previous
        }
        return resp.ok(data=users, pagination=pagination)
    except Exception as e:
        # 记录错误日志
        logger.error(f"Error fetching users: {e}")
        return resp.fail(resp.ServerError)


@router.post("/upload/file", summary="测试上传图片")
async def test_upload_image(
        file: UploadFile = File(...),
):
    # 本地存储临时方案，一般生产都是使用第三方云存储OSS(如七牛云, 阿里云)
    # 建议计算并记录一次 文件md5值 避免重复存储相同资源
    save_dir = f"{settings.BASE_PATH}/static/img"

    if not os.path.exists(save_dir):
        os.mkdir(save_dir)
    try:
        # 获取文件的后缀名，然后将这个后缀名赋值给变量 suffix
        suffix = Path(file.filename).suffix
        # 临时文件名
        with NamedTemporaryFile(delete=False, suffix=suffix, dir=save_dir) as tmp:
            # 将上传的文件保存到临时文件中
            shutil.copyfileobj(file.file, tmp)
            tmp_file_name = Path(tmp.name).name
    finally:
        file.file.close()

    return resp.ok(data={"image": f"/static/img/{tmp_file_name}"})


@router.post("/upload/files", summary="测试上传多个文件")
async def test_upload_files(files: List[UploadFile] = File(...)):
    save_dir = f"{settings.BASE_PATH}/static/img"
    if not os.path.exists(save_dir):
        os.mkdir(save_dir)
    for file in files:
        logger.info(file.filename)
        suffix = Path(file.filename).suffix
        logger.info(suffix)
    return resp.ok(data={"files": len(files)})


@router.post("/request", summary="测试获取请求信息")
async def test_post_request(request: Request, db: AsyncSession = Depends(get_db)):
    logger.info(request.url)
    logger.info(request.client.host)
    logger.info(request.headers)
    logger.info(request.headers.get("User-Agent"))
    logger.info(request.query_params)
    logger.info(request.cookies)
    return resp.ok(data={"request": "ok"})


@router.post("/response", response_model=UserOut, summary="测试自定义响应")
async def test_post_response(user: UserIn, db: AsyncSession = Depends(get_db)):
    return user


@router.get("/jinja2", summary="测试jinja2模版服务端渲染(SSR)")
async def test_jinja2(request: Request, db: AsyncSession = Depends(get_db)):
    return templates.TemplateResponse("index.html", {"request": request, "title": "测试jinja2模版服务端渲染(SSR)"})


@router.get("/redis", summary="测试redis使用")
async def test_redis(
        *,
        bar: str = Query(..., title="测试字段", description="测试字段描述")
) -> Any:
    """
    测试redis使用
    :param bar:
    :return:
    """
    redis_client.set("test_redis", bar, ex=60)
    redis_test = redis_client.get("test_redis")

    return resp.ok(data=redis_test)


@router.get("/asyncio", summary="测试异步性能")
async def test_asyncio():
    await asyncio.sleep(1)
    return resp.ok(data="测试完成")


@router.get("/syncio", summary="测试同步性能")
async def test_syncio():
    time.sleep(1)
    return resp.ok(data="测试完成")


@router.get("/{xxx}", summary="测试路径参数、查询参数并存")  # Optional[str] 相当于Union[str, None]
async def test_get_user_by_x(xxx: str, q1: Union[str, None] = None, q2: Optional[str] = None,
                             db: AsyncSession = Depends(get_db)):
    return resp.ok(data={"xxx": xxx, "q1": q1, "q2": q2})
